/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry.protocol;

import io.sentry.DateUtils;
import io.sentry.SentryBaseEvent;
import io.sentry.SentryTracer;
import io.sentry.Span;
import io.sentry.SpanContext;
import io.sentry.SpanStatus;
import io.sentry.util.Objects;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * SentryTransaction
 *
 * @since 2021-06-02
 */
@ApiStatus.Internal
public final class SentryTransaction extends SentryBaseEvent {
    /**
     * The transaction name.
     */
    @SuppressWarnings("UnusedVariable")
    private @Nullable String transaction;

    /**
     * The moment in time when span was started.
     */
    private final @NotNull Date startTimestamp;

    /**
     * The moment in time when span has ended.
     */
    private @Nullable Date timestamp;

    /**
     * A list of spans within this transaction. Can be empty.
     */
    private final @NotNull List<SentrySpan> spans = new ArrayList<>();

    /**
     * The {@code type} property is required in JSON payload sent to Sentry.
     */
    @SuppressWarnings("UnusedVariable")
    private @NotNull
    final String type = "transaction";

    /**
     * constructor
     *
     * @param sentryTracer sentryTracer
     */
    @SuppressWarnings("deprecation")
    public SentryTransaction(final @NotNull SentryTracer sentryTracer) {
        super(sentryTracer.getEventId());
        Objects.requireNonNull(sentryTracer, "sentryTracer is required");
        this.startTimestamp = sentryTracer.getStartTimestamp();
        this.timestamp = DateUtils.getCurrentDateTime();
        this.transaction = sentryTracer.getName();
        for (final Span span : sentryTracer.getChildren()) {
            this.spans.add(new SentrySpan(span));
        }
        final Contexts contexts = this.getContexts();
        for (Map.Entry<String, Object> entry : sentryTracer.getContexts().entrySet()) {
            contexts.put(entry.getKey(), entry.getValue());
        }
        contexts.setTrace(sentryTracer.getSpanContext());
        this.setRequest(sentryTracer.getRequest());
    }

    public @NotNull List<SentrySpan> getSpans() {
        return spans;
    }

    /**
     * isFinished
     *
     * @return boolean
     */
    public boolean isFinished() {
        return this.timestamp != null;
    }

    public @Nullable String getTransaction() {
        return transaction;
    }

    public @NotNull Date getStartTimestamp() {
        return startTimestamp;
    }

    public @Nullable Date getTimestamp() {
        return timestamp;
    }

    /**
     * get type
     *
     * @return type
     */
    public @NotNull String getType() {
        return type;
    }

    /**
     * get status
     *
     * @return SpanStatus
     */
    public @Nullable SpanStatus getStatus() {
        final SpanContext trace = this.getContexts().getTrace();
        return trace != null ? trace.getStatus() : null;
    }

    /**
     * is sampled
     *
     * @return boolean
     */
    public boolean isSampled() {
        final SpanContext trace = this.getContexts().getTrace();
        return trace != null && Boolean.TRUE.equals(trace.getSampled());
    }
}
